#第四部分
#第八章 对象引用、可变性和垃圾回收

#python的不可变类似都是可散列的(例如 tuple ),用户自定义的对象都是可散列的

#为任意对象做深复制和浅复制 copy 模块

import copy

class Bus():
    def __init__(self,passengers):
        self.passengers = passengers
    def pick(self,name):
        self.passengers.append(name)

    def drop(self,name):
        self.passengers.remove(name)
    def __repr__(self):
        return "<object Bus %s >" %("-".join(self.passengers))

bus1 = Bus(['bill','james','jack','paul'])
bus2 = copy.copy(bus1) #浅复制
bus3 = copy.deepcopy(bus1) #深度复制

bus1.drop('jack')
print(bus1,bus2,bus3)

#循环引用的多层深度复制
a = [1,2,3]
b = [4,5,6]
a.append(b)
c = copy.deepcopy(a) # a中的b元素也会被深度复制
d = copy.copy(a)
b.remove(5)
print(a,c,d)

#一段监控对象被回收的代码

import weakref

s1 = {1,2,3,4}
s2 = s1 
def byt():
    print("对象回收了")

weakref.finalize(s1,byt) #注册函数 对象被回收的时候函数被回调

del s1 # 只是删除对象的引用s1 没有回收对象 因为对象还有一个引用s2
del s2 #再执行删除s2 对象没有引用了 会被回收

#弱引用

a_set = {1,2}
weak = weakref.ref(a_set)
print(weak()) #返回被引用的对象

a_set={1,2,3} #重新赋值给a_set引用 原来的对象则没有引用了
print(weak()) # 显示None 说明已经回收原来的引用

#弱引用集合

class Cheese():
    def __init__(self,kind):
        self.kind = kind
    def __repr__(self):
        return "<Cheese %s>"%self.kind
#弱引用值字典 它的值如果被删除了 那么字典中的键值也不复存在了,引用计算法不会计算弱引用
wvd = weakref.WeakValueDictionary() 

cheeses = [Cheese('Red Leicester'),Cheese('Tilist'),Cheese('Brie'),Cheese('Parmesan')]
for cheese in cheeses:
    wvd[cheese.kind] = cheese
    

print(list(wvd.keys()),cheeses)

del cheeses
print(list(wvd.keys()),len(wvd)) #这个时候还会输出一个键,原因是for循环里面的cheese是一个全局引用,还没删除 它是对最后一个对象的引用

del cheese
print(list(wvd.keys()),len(wvd)) #全部对象都已经回收了












